//
// Created by Administrator on 2021/4/21.
//

/*
一条包含字母A-Z 的消息通过以下映射进行了 编码 ：

'A' -> 1
'B' -> 2
...
'Z' -> 26
要 解码 已编码的消息，所有数字必须基于上述映射的方法，反向映射回字母（可能有多种方法）。例如，"11106" 可以映射为：

"AAJF" ，将消息分组为 (1 1 10 6)
"KJF" ，将消息分组为 (11 10 6)
注意，消息不能分组为 (1 11 06) ，因为 "06" 不能映射为 "F" ，这是由于 "6" 和 "06" 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ，请计算并返回 解码 方法的 总数 。

题目数据保证答案肯定是一个 32 位 的整数。


示例 1：
输入：s = "12"
输出：2
解释：它可以解码为 "AB"（1 2）或者 "L"（12）。

示例 2：
输入：s = "226"
输出：3
解释：它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

示例 3：
输入：s = "0"
输出：0
解释：没有字符映射到以 0 开头的数字。
含有 0 的有效映射是 'J' -> "10" 和 'T'-> "20" 。
由于没有字符，因此没有有效的方法对此进行解码，因为所有数字都需要映射。

示例 4：
输入：s = "06"
输出：0
解释："06" 不能映射到 "F" ，因为字符串含有前导 0（"6" 和 "06" 在映射中并不等价）。

提示：

1 <= s.length <= 100
s 只包含数字，并且可能包含前导零。

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/decode-ways
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。*/
#include <vector>
#include <iostream>
#include <string>
#include <tuple>

using namespace std;

class Solution {
public:
    int numDecodings(string s) {
        /**dp
         * 如果s[i] s[i-1]能组合成10-26的数字，则
         * f[i] = f[i-1]+f[i-2]
         * 否则：
         * f[i] = f[i-1]
         * **/
        auto n = s.size();
        vector<int> dp(n + 1, 0);
        dp[0] = 1;
        if (s[0] == '0') return 0;
        for (int i = 1; i <= n; ++i) {
            if (s[i - 1] != '0') { // i位不为0，才能单独存在
                dp[i] = dp[i - 1];
            }
            if (i == 1) continue;
            int num = stoi(s.substr(i - 2, 2));
            if (num >= 10 and num <= 26) {
                dp[i] += dp[i - 2];
            }
            // 若连续存在0，则未发生更新
        }
        return dp.back();
    }
};

class Solution2 { // 题解1 思路和自己想的一致，但是在处理0时要注意
public:
    int numDecodings(string s) {
        auto n = s.size();
        vector<int> f(n + 1);
        f[0] = 1;
        for (int i = 1; i <= n; ++i) {
            if (s[i - 1] != '0') {
                f[i] += f[i - 1];
            }
            if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) {
                f[i] += f[i - 2];
            }
        }
        return f[n];
    }
};

class Solution3 { // 题解 不构造数组，只用3个变量代替
public:
    int numDecodings(string s) {
        int n = s.size();
        // a = f[i-2], b = f[i-1], c = f[i]
        int a = 0, b = 1, c;
        for (int i = 1; i <= n; ++i) {
            c = 0;
            if (s[i - 1] != '0') {
                c += b;
            }
            if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) {
                c += a;
            }
            tie(a, b) = {b, c};
        }
        return c;
    }
};

int main() {
    Solution sol;
    cout << sol.numDecodings(string{"12"}) << endl;
    cout << sol.numDecodings(string{"226"}) << endl;
    cout << sol.numDecodings(string{"0"}) << endl;
    cout << sol.numDecodings(string{"06"}) << endl;
    cout << sol.numDecodings(string{"123123"}) << endl;
    cout << sol.numDecodings(string{"11106"}) << endl;
    cout << sol.numDecodings(string{"10"}) << endl;
    return 0;
}